---------------------------------------- Chapitre I - Les bases ----------------------------------------
Crackme2 - partie 1
Cible : CrackMe2
Outils nécessaires :
OllyDbg (by Oleh Yuschuk)
Passons maintenant au Crackme2, disponible dans le dossier "Pack / Chapitre I / 4 - Crackme2 / CrackMe2.rar". Comme le 1er, il a été écrit en assembleur afin de simplifier le code. Ouvrez le, tapez un nom et un serial bidon, OK et on a le message d'erreur :
On ouvre Olly, menu File / Open (ou F3) et on sélectionne le Crackme2. Comme vu précédemment, on va chercher notre string "Serial incorrect". Clic droit dans le code, Search for / All referenced strings et là rien ne se passe ! Rien, excepté un surlignage jaune assez rapide en bas de la fenêtre de Olly :
On a quand même le temps de lire "No items found" (Aucun résultat trouvé) avant que la barre d'information ne revienne à sa couleur normale et affiche de nouveau "Entry point of main module". Cela signifie qu'il n'y a aucune chaîne de caractères ASCII reconnaissable dans notre programme. Comment est-ce possible alors que l'on a le message " Serial incorrect !" qui s'affiche ? Tout simplement car lors de l'écriture du programme il a été prévu de les masquer pour éviter, par exemple, de donner des pistes aux reversers. Il existe de nombreuses techniques pour y parvenir (encodage, cryptage, chaînes dans un fichier annexe, etc). Pour vous donner un exemple simple, prenons par exemple le caractère A. Sa valeur hexadécimale dans la table ASCII est 41h. Imaginons que je stocke 140h, valeur se trouvant en dehors de la table ASCII étendue. Lors de la recherche de strings, Olly ne verra pas cette valeur comme un caractère lisible dans une chaîne et donc l'ignorera. Maintenant, lors de la création d'une string où il faut un A, je demande au programme de prendre cette valeur et de lui soustraire FFh. J'aurais donc 140h - FFh = 41h soit la valeur de mon A. En faisant le même genre de manipulation pour tous les caractères nécessaires, le tour est joué, il n'y a plus de strings visibles !
Il nous faut donc un autre moyen pour trouver où poser un BP intéressant. Pour cela, on va utiliser les APIs de Windows.
Ce sont des fonctions permettant d'exploiter Windows de façon simplifiée. Lors de l'écriture d'un programme, on fait appel aux APIs en leur passant simplement quelques paramètres pour effectuer différentes actions : accès à la base de registre, lecture/écriture de fichiers, affichage de boites de dialogue, etc. Leurs noms indiquent de façon assez explicite leurs rôles : GetWindowText, MessageBox, CreateFile, RegCreateKey, etc. Elles sont regroupées par type dans des fichiers de type DLL (Dynamic Link Library) tel que : User32.dll, Kernel32.dll, etc. Vous trouverez les différentes APIs et leurs fonctions sur la MSDN (MicroS oft Developer Network platforms) et une liste des principales dans le fichier d'aide Ollydbg.hlp fourni dans le pack (Pack / Chapitre 01 / 1 - Aide Ollydbg).
Revenons à notre crackme. Comment les APIs vont-elles pouvoir nous aider ? Dans le code, faites un clic droit, Search for / Names ou, plus rapide, utilisez le raccourci CTRL+N. Dans la nouvelle fenêtre qui s'ouvre sont listées toutes les APIs utilisées par le programme. En regardant leurs noms, on repère vite quelque chose d'intéressant : GetDlgItemTextA :
C'est la fonction qui permet de récupérer du texte dans une boite de dialogue. Sélectionnez la, clic droit, Find references (ou CTRL+R) et on a encore une nouvelle fenêtre. Dans celle-ci, nous pouvons voir toutes les adresses dans notre programme où notre API est appelée :
La troisième ligne étant l'appel direct vers la DLL, on va se concentrer sur les deux premières. En commentaires,
Olly nous ajoute gentiment l'ID (IDentifiant) du contrôle dans lequel va être
récupéré le texte. On peut donc vérifier dans la fenêtre windows. Lancez le programme avec F9 (ou
) puis cliquez sur
:
Si vous n'avez pas la même présentation que moi, faites un clic droit dans une partie vide de la fenêtre, Sort by
et sélectionnez Parent. De cette manière, tous les contrôles seront rattachés à la fenêtre
dont ils dépendent (fenêtre parent). On retrouve nos 2 ID (1002 et 1003) correspondants à des contrôles
Edit (zone de texte) dans la fenêtre "XTX : Cracking Progressif - Crackme2". Et nous
avons bien 2 zones de textes dans notre crackme : Nom et Serial. On revient dans la fenêtre
References ( ) et on pose un BP avec F2
sur les deux premières lignes. On saisit un couple name/serial (Kirjo / 12345), OK et Olly breake.
Un petit F8 (ou
) et nous avons ceci :
La string récupérée par la fonction est apparue. Il s'agit ce coup-ci du nom, dans le contrôle ID1002
et on peut voir dans la pile qu'il est stocké à l'adresse 403350. F9 ( ou
), on breake sur le 2eme BP, F8 (ou
) pour exécuter la fonction :
On a maintenant le serial, récupéré dans le contrôle ID1003, stocké à l'adresse 403170. Positionnez-vous dans le dump, faites un clic droit, Goto / Expression (ou CTRL + G). Dans la boîte de dialogue, saisissez dans la case "Enter address expression" l'adresse du serial : 403170 puis OK. Le dump se positionne sur l'adresse saisie :
On va utiliser un petit truc pour faciliter la lecture du code. Faites un clic sur le début du serial (31 ou le 1 dans la colonne ASCII) pour le sélectionner. Taper ":" (ou clic droit / Add label...). Dans la boite de dialogue, tapez "serial" puis OK. Avant cette petite manipulation, les lignes dans le code faisant référence à cette adresse apparaissaient comme ça :
Dorénavant, on lira ceci :
Au même endroit, on va maintenant poser un Break Point Memory (BPM). Ce sont des points d'arrêt
que l'on peut poser sur des emplacements mémoire. On peut choisir si Olly breakera sur Read access (lecture du contenu
de l'emplacement), Write access (écriture de données sur cet emplacement) ou Execution.
Faites un clic droit sur le 31, Breakpoint / Memory ..., puis dans la boite de dialogue cochez
Read Access. Chaque fois que le serial sera lu, Olly breakera et on pourra regarder ce que le programme en fait (comparaison avec le
bon serial par exemple ...). On relance avec F9 ( ou ) et on breake ici :
Ici, nous sommes dans le module KERNELBASE, aucun intérêt pour nous. Encore F9 (ou
) et cette fois ci on revient dans notre programme :
En traçant avec F8 (ou ) on analyse facilement ce qui se passe
dans cette boucle (voir les commentaires). A la fin de celle-ci, on voit dans le dump notre serial modifié mais ce n'est donc pas ici qu'il est comparé.
Notre BPM étant toujours actif et le serial modifié étant à la place du serial original, on continue avec
F9 (ou
). Olly breake à nouveau :
Voilà un endroit beaucoup plus intéressant ! Première chose que l'on remarque, c'est que l'adresse de notre serial modifié est
chargée dans ESI (1). On analyse ensuite en traçant avec F8 (ou
) la boucle qui suit (2). On voit que notre serial modifié est
comparé à la string dont l'adresse est indiquée par EDI (3), soit
"JBFE" et si la comparaison n'est pas bonne, on sort de la boucle. Solution la plus simple : on remplace le
JNE par des NOPs comme on l'avait fait pour le crackme précédent. Solution plus élégante : on essaye de trouver le bon serial à saisir. C'est ici relativement
simple.
On a vu que le serial était modifié par un simple XOR 0Fh sur chaque caractère. Cette opération marchant dans les 2 sens (si 45h XOR 0Fh = 4A h alors 4Ah XOR 0Fh = 45h), il suffit de l'appliquer sur les caractères du bon serial pour trouver celui à saisir. Il suffit de regarder dans le dump (4) pour avoir les valeurs ASCII de chaque caractère ce qui nous donne :
Saisissez notre nouveau couple name/serial ("Kirjo" / "EMIJ"), OK et :
Voilà, on a utilisé deux techniques : le patching et le fishing. Mais il existe une 3eme solution ...